package com.example;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class MyRouteDefinitionRepository implements RouteDefinitionRepository {
    @Autowired
    private ApplicationEventPublisher publisher;

    private boolean deleteRoute = false;

    /*
     *  该方法用于获取所有存储的路由定义信息，返回一个Flux<RouteDefinition>流式响应，网关启动时会调用此方法来加载所有路由规则。在默认的InMemoryRouteDefinitionRepository实现中，该方法从内存中返回路由配置
     */
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        log.info("getRouteDefinitions");
        try {
            if (deleteRoute) {
                log.info("delete route");
                throw new Exception("all route definitions have been deleted");
            }
            return Flux.fromIterable(this.loadRouteDefinitions());
        } catch (Exception e) {
            return Flux.empty();
        }
    }

    private List<RouteDefinition> loadRouteDefinitions() throws URISyntaxException {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        RouteDefinition routeDefinition = new RouteDefinition();
        routeDefinition.setId("server-a");

        routeDefinition.setPredicates(new ArrayList<>());
        PredicateDefinition predicateDefinition = new PredicateDefinition();
        predicateDefinition.setName("Host");
        Map<String, String> args = new HashMap<>();
        args.put("pattern", "server-a.lo*");

        predicateDefinition.setArgs(args);
        routeDefinition.getPredicates().add(predicateDefinition);

        routeDefinition.setUri(new URI("lb://server-a"));

        routeDefinitions.add(routeDefinition);
        return routeDefinitions;
    }

    /*
     *  该方法用于保存或更新单个路由配置，接收一个包含RouteDefinition的Mono对象作为参数，并返回Mono<Void>表示操作完成。当需要动态添加或修改路由时，通过此方法将新的路由定义持久化到存储介质中。
     */
    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        log.info("save");
        return route.flatMap(routeDefinition -> {
            return Mono.empty();
        });
    }

    /*
     * 该方法用于根据路由ID删除指定的路由配置，接收包含路由ID的Mono对象，同样返回Mono<Void>。这允许在运行时移除不再需要的路由规则。
     */
    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        log.info("delete");
        return routeId.flatMap(id -> {
            return Mono.empty();
        });
    }

    /*
     * 这里是定义的一个模拟外部刷新routes的方法
     */
    public void refreshRoutes(boolean deleteRoute) {
        this.deleteRoute = deleteRoute;
        log.info("refreshRoutes");
        publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}
